跳到主要内容

Go new 与 make 的区别

new 是怎么工作的?

在 Go 中,new 是一个内置函数,用于动态分配类型的零值并返回其指针。

new 函数的语法如下:

func new(Type) *Type

Type 是一个类型,可以是内置类型(如 intfloat64bool 等)或自定义类型(如结构体、接口等)。

new 函数的工作原理如下:

  1. 首先,new 函数接收一个类型作为参数,例如 new(int)new(MyStruct)
  2. new 函数分配了足够的内存来存储所指定类型的零值,并返回该类型的指针。
  3. 分配的内存空间被初始化为类型的零值,对于基本类型是对应类型的零值(例如 0false),对于结构体则是所有字段都被初始化为各自类型的零值。
  4. new 函数返回一个指向所分配内存的指针。

使用 new 函数可以方便地在堆上分配内存,并获得一个指向该内存的指针。例如:

package main

import "fmt"

type Person struct {
Name string
Age int
}

func main() {
p := new(Person)
fmt.Println(p) // 输出:&{ 0}
}

在上述示例中,使用 new(Person) 分配了一个 Person 类型的零值,并返回一个指向该内存的指针 p。输出 p 的值为 &{ 0},表示一个 Person 类型的指针,其 Name 字段为空字符串,Age 字段为 0

需要注意的是,使用 new 分配的内存空间会在不再被引用时由 Go 的垃圾回收器自动释放,无需手动释放。

make 是怎么工作的?

在 Go 中,make 是一个用于创建切片、映射和通道的内建函数。它的工作原理与 new 函数不同。

当使用 make 创建切片、映射或通道时,它会分配并初始化底层的数据结构,并返回一个已初始化的引用(即切片、映射或通道的值)。这些数据结构具有适当的大小和内部字段,以便支持切片、映射和通道的操作。

具体来说,make 函数的工作流程如下:

  1. 接收类型和参数:make 函数接收一个类型参数和可能的其他参数,具体参数的含义取决于所创建的类型。例如,创建切片时,make 函数接收切片的类型和长度。

  2. 分配内存:make 函数根据参数指定的类型和大小,动态分配足够的内存来存储底层数据结构。这些数据结构包含用于管理切片、映射或通道的元数据和内部字段。

  3. 初始化数据结构:分配的内存通过初始化数据结构来建立切片、映射或通道的基本结构。这些初始化操作确保数据结构的一致性,并准备好后续的操作。

  4. 返回引用:make 函数返回一个已初始化的引用(即切片、映射或通道的值),可以将其分配给变量并在代码中使用。

需要注意的是,make 函数只适用于创建切片、映射和通道,并不适用于创建其他类型的值。对于其他类型的值,可以使用 new 函数来分配内存。

以下是一些示例代码,演示了如何使用 make 函数创建切片、映射和通道:

package main

import "fmt"

func main() {
// 创建切片
slice := make([]int, 5, 10)
fmt.Println(slice)

// 创建映射
mapping := make(map[string]int)
mapping["a"] = 1
mapping["b"] = 2
fmt.Println(mapping)

// 创建通道
channel := make(chan int)
go func() {
channel <- 42
}()
value := <-channel
fmt.Println(value)
}

在上述示例中,我们使用 make 函数创建了一个切片 slice,一个映射 mapping 和一个通道 channelmake 函数分别为每种类型分配了适当的内存,并返回已初始化的引用。这些引用可以用于后续的切片、映射和通道操作。

总结而言,make 函数在创建切片、映射和通道时,动态分配内存并初始化底层数据结构,返回一个已初始化的引用。这使得使用切片、映射和通道更加方便和安全。

makemap 函数是怎么和 make 关联上的

在 Go 中,makemap 是 Go 编译器内部生成的函数,用于创建映射(map)。虽然我们在代码中使用的是 make 函数来创建映射,但实际上 make 函数只是对 makemap 函数的一个包装。

当编译器遇到 make(map[KeyType]ValueType) 语句时,它会将其转换为 makemap 函数的调用,传递相应的参数。这个转换是在编译阶段完成的,并且对开发者来说是透明的。

makemap 函数的实现是在 Go 编译器的源代码中完成的,而不是在 Go 代码中。它负责分配内存、初始化数据结构,并返回一个初始化的映射值。具体的实现细节会因为不同的编译器实现和版本而有所差异。

需要强调的是,makemap 函数是编译器内部的实现细节,开发者无法直接访问或调用它。我们应该使用 make 函数来创建映射,而无需关心 makemap 函数的具体实现。这种封装使得代码编写和理解更加简洁和方便。